﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using STSdb.MTL.Utils.Serialization;

namespace STSdb.MTL
{
    /// <summary>
    /// This class is a part of every class Transaction.
    /// Holds definitions for NonGeneric Method calls.
    /// For now supports limited set of methods.
    /// </summary>
    public class TransactionNonGenerics
    {
        Transaction _transaction = null;

        public TransactionNonGenerics(Transaction transaction)
        {
            this._transaction = transaction;
        }


        /*
         * EXAMPLES
            string res = tran.NonGenerics.Select("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "1");

            string res = tran.NonGenerics.SelectForward("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", 1);
            string res = tran.NonGenerics.SelectForwardStartKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ","3",5);
            string res = tran.NonGenerics.SelectForwardStartEndKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ","1", "3", 5);
         
            string res = tran.NonGenerics.SelectBackward("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", 2);
            string res = tran.NonGenerics.SelectBackwardLastKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "3", 5);
            string res = tran.NonGenerics.SelectBackwardLastFirstKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "20", "3", 5);
          
            string res = tran.NonGenerics.Count("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ");
            string res = tran.NonGenerics.MaxRow("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ");
            string res = tran.NonGenerics.MinRow("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ");
         * 
         */


        #region "SELECT"
        /// <summary>
        /// Returns serialized STSdbMTl.TableRow[keyType,valueType].
        /// <para>
        /// <example>string return = tran.NonGenerics.Select("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "1");</example>
        /// </para>
        /// </summary>
        /// 
        /// <param name="tableName">table name</param>
        /// <param name="keyType">Type.GetType("System.Int32")</param>
        /// <param name="valueType">Type.GetType("MyApplication.Objects.Car") the call is wrapped out from external layer who has "visibility" of all objects</param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="key">key which we search as string</param>
        /// <returns>Serialized STSdb.MTL.TableRow[keyType,valueType]</returns>
        public string Select(string tableName, Type keyType, Type valueType, string selectMode, string key)
        {
            string res = String.Empty;

            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/Select");

            
            
            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[3];
            pars[0] = tableName;
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO
            pars[2] = Convert.ChangeType(key, keyType);     //searching key, key we supply as string     

            var tr = mi_constructed.Invoke(this._transaction, pars);

            res = tr.SerializeXml();

            //Type tbrOpenType = typeof(STSdb.MTL.TableRow<,>);                                   //THESE CAN LIVE AS STATIC METHOD IN TableRowClass
            //Type tbrCloseType = tbrOpenType.MakeGenericType(myKey, myValue);                    //

            //var tbrKeyExists = STSdb.MTL.CachedReflections.Get_FastPropertyAccessor(tr, tbrCloseType, "Exists");


            //if (!(bool)tbrKeyExists)
            //{
            //    Console.WriteLine("@@@@@NO RESULT");
            //    return;             //NO RESULT FOUND IN DB //WE CAN SEND RESULT VALUE VIA WIRES
            //}

            //var tbrValue = STSdb.MTL.CachedReflections.Get_FastPropertyAccessor(tr, tbrCloseType, "Value");
            //var tbrKey = STSdb.MTL.CachedReflections.Get_FastPropertyAccessor(tr, tbrCloseType, "Key");

            ////SERIALIZING VALUE TO STRING

            //string serializedValue1 = "NULL"; //MEANS DEFAULT NULL VALUE
            //if (tbrValue != null)
            //{
            //    serializedValue1 = SerializeXml(tbrValue);
            //}

            return res;
        }
        #endregion

        #region "SELECT FORWARD"
        /// <summary>
        /// string res = tran.NonGenerics.SelectForward("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", 10);
        /// </summary>
        /// <param name="tableName">table name</param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="quantity">Quantity of values to be returned</param>
        /// <returns>Serialized List[STSdb.MTL.TableRow[keyType,valueType]]</returns>
        public string SelectForward(string tableName, Type keyType, Type valueType, string selectMode, int quantity)
        {

            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/SelectForward");

            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[2];
            pars[0] = tableName;   //we supply table name as string           
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO            

            var tr = mi_constructed.Invoke(this._transaction, pars);

            Type tp2 = typeof(STSdb.MTL.TableRow<,>);
            Type tb2c = tp2.MakeGenericType(keyType, valueType);

            Type lst = typeof(List<>);
            Type lst2c = lst.MakeGenericType(tb2c); //Forming List<TableRow<keyType,valueType>>()

            object olist = Activator.CreateInstance(lst2c); //activing List

            int q = 0;

            if (quantity < 1)
                quantity = 1;

            foreach (object o in (tr as IEnumerable))       //namespace System.Collections.IEnumerable;
            {
                ((IList)olist).Add(o);
                
                q++;
                if (q == quantity)          //implementing Take N
                    break;
            }

            return olist.SerializeXml();
        }


        /// <summary>
        /// Select forward with supplied Start Key
        /// string res = tran.NonGenerics.SelectForwardStartKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "3", 10);
        /// </summary>
        /// <param name="tableName">table name</param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="quantity">Quantity of values to be returned</param>
        /// <returns>Serialized List[STSdb.MTL.TableRow[keyType,valueType]]</returns>
        public string SelectForwardStartKey(string tableName, Type keyType, Type valueType, string selectMode, string startKey, int quantity)
        {
            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/SelectForwardStartKey");

            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[3];
            pars[0] = tableName;   //we supply table name as string           
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO            
            pars[2] = Convert.ChangeType(startKey, keyType);

            var tr = mi_constructed.Invoke(this._transaction, pars);

            Type tp2 = typeof(STSdb.MTL.TableRow<,>);
            Type tb2c = tp2.MakeGenericType(keyType, valueType);

            Type lst = typeof(List<>);
            Type lst2c = lst.MakeGenericType(tb2c); //Forming List<TableRow<keyType,valueType>>()

            object olist = Activator.CreateInstance(lst2c); //activing List

            int q = 0;

            if (quantity < 1)
                quantity = 1;

            foreach (object o in (tr as IEnumerable))       //namespace System.Collections.IEnumerable;
            {
                ((IList)olist).Add(o);

                q++;
                if (q == quantity)          //implementing Take N
                    break;
            }

            return olist.SerializeXml();
        }


        /// <summary>
        /// Select forward with supplied Start and End Keys
        /// string res = tran.NonGenerics.SelectForwardStartEndKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "3","10", 10);
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="quantity">Quantity of values to be returned</param>
        /// <returns>Serialized List[STSdb.MTL.TableRow[keyType,valueType]]</returns>
        public string SelectForwardStartEndKey(string tableName, Type keyType, Type valueType, string selectMode, string startKey,string endKey, int quantity)
        {   

            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/SelectForwardStartEndKey");

            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[4];
            pars[0] = tableName;   //we supply table name as string           
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO            
            pars[2] = Convert.ChangeType(startKey, keyType);
            pars[3] = Convert.ChangeType(endKey, keyType);

            var tr = mi_constructed.Invoke(this._transaction, pars);

            Type tp2 = typeof(STSdb.MTL.TableRow<,>);
            Type tb2c = tp2.MakeGenericType(keyType, valueType);

            Type lst = typeof(List<>);
            Type lst2c = lst.MakeGenericType(tb2c); //Forming List<TableRow<keyType,valueType>>()

            object olist = Activator.CreateInstance(lst2c); //activing List

            int q = 0;

            if (quantity < 1)
                quantity = 1;

            foreach (object o in (tr as IEnumerable))       //namespace System.Collections.IEnumerable;
            {
                ((IList)olist).Add(o);

                q++;
                if (q == quantity)          //implementing Take N
                    break;
            }

            return olist.SerializeXml();
        }
        #endregion

        #region "SELECT BACKWARD"
        /// <summary>
        /// string res = tran.NonGenerics.SelectBackward("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", 10);
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="quantity">Quantity of values to be returned</param>
        /// <returns>Serialized List[STSdb.MTL.TableRow[keyType,valueType]]</returns>
        public string SelectBackward(string tableName, Type keyType, Type valueType, string selectMode, int quantity)
        {

            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/SelectBackward");

            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[2];
            pars[0] = tableName;   //we supply table name as string           
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO            

            var tr = mi_constructed.Invoke(this._transaction, pars);

            Type tp2 = typeof(STSdb.MTL.TableRow<,>);
            Type tb2c = tp2.MakeGenericType(keyType, valueType);

            Type lst = typeof(List<>);
            Type lst2c = lst.MakeGenericType(tb2c); //Forming List<TableRow<keyType,valueType>>()

            object olist = Activator.CreateInstance(lst2c); //activing List

            int q = 0;

            if (quantity < 1)
                quantity = 1;

            foreach (object o in (tr as IEnumerable))       //namespace System.Collections.IEnumerable;
            {
                ((IList)olist).Add(o);

                q++;
                if (q == quantity)          //implementing Take N
                    break;
            }

            return olist.SerializeXml();
        }


        /// <summary>
        /// Select forward with supplied Start Key
        /// string res = tran.NonGenerics.SelectBackwardLastKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "3", 10);
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="quantity">Quantity of values to be returned</param>
        /// <returns>Serialized List[STSdb.MTL.TableRow[keyType,valueType]]</returns>
        public string SelectBackwardLastKey(string tableName, Type keyType, Type valueType, string selectMode, string lastKey, int quantity)
        {
            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/SelectBackwardLastKey");

            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[3];
            pars[0] = tableName;   //we supply table name as string           
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO            
            pars[2] = Convert.ChangeType(lastKey, keyType);

            var tr = mi_constructed.Invoke(this._transaction, pars);

            Type tp2 = typeof(STSdb.MTL.TableRow<,>);
            Type tb2c = tp2.MakeGenericType(keyType, valueType);

            Type lst = typeof(List<>);
            Type lst2c = lst.MakeGenericType(tb2c); //Forming List<TableRow<keyType,valueType>>()

            object olist = Activator.CreateInstance(lst2c); //activing List

            int q = 0;

            if (quantity < 1)
                quantity = 1;

            foreach (object o in (tr as IEnumerable))       //namespace System.Collections.IEnumerable;
            {
                ((IList)olist).Add(o);

                q++;
                if (q == quantity)          //implementing Take N
                    break;
            }

            return olist.SerializeXml();
        }


        /// <summary>
        /// Select forward with supplied Start and End Keys
        /// string res = tran.NonGenerics.SelectBackwardLastFirstKey("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ", "10","3", 10);
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <param name="quantity">Quantity of values to be returned</param>
        /// <returns>Serialized List[STSdb.MTL.TableRow[keyType,valueType]]</returns>
        public string SelectBackwardLastFirstKey(string tableName, Type keyType, Type valueType, string selectMode, string lastKey, string firstKey, int quantity)
        {

            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/SelectBackwardLastFirstKey");

            //CONVERTING METHOD TO GENERIC
            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);

            object[] pars = new object[4];
            pars[0] = tableName;   //we supply table name as string           
            pars[1] = Enum.Parse(typeof(STSdb.MTL.eSelectMode), selectMode);  //we supply select mode as string can be also READ_SYNCHRO            
            pars[2] = Convert.ChangeType(lastKey, keyType);
            pars[3] = Convert.ChangeType(firstKey, keyType);

            var tr = mi_constructed.Invoke(this._transaction, pars);

            Type tp2 = typeof(STSdb.MTL.TableRow<,>);
            Type tb2c = tp2.MakeGenericType(keyType, valueType);

            Type lst = typeof(List<>);
            Type lst2c = lst.MakeGenericType(tb2c); //Forming List<TableRow<keyType,valueType>>()

            object olist = Activator.CreateInstance(lst2c); //activing List

            int q = 0;

            if (quantity < 1)
                quantity = 1;

            foreach (object o in (tr as IEnumerable))       //namespace System.Collections.IEnumerable;
            {
                ((IList)olist).Add(o);

                q++;
                if (q == quantity)          //implementing Take N
                    break;
            }

            return olist.SerializeXml();
        }
        #endregion

        #region "MAX, MIN, COUNT"

        /// <summary>
        /// Returns count of rows in a table as string
        /// <para>string res = tran.NonGenerics.Count("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ");</para>
        /// </summary>
        /// <param name="tableName">table name</param>
        /// <param name="keyType">Type.GetType("System.Int32")</param>
        /// <param name="valueType">Type.GetType("MyApplication.Objects.Car") the call is wrapped out from external layer who has "visibility" of all objects</param>
        /// <param name="selectMode">READ or READ_SYNCHRO</param>
        /// <returns></returns>
        public string Count(string tableName, Type keyType, Type valueType, string selectMode)
        {       
            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/CountWithPossibleLocking");

            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);
            object[] pars = new object[2];
            pars[0] = tableName;
            pars[1] = selectMode.Equals("READ_SYNCHRO") ? true : false;  //we supply select mode as string can be also READ_SYNCHRO

            return mi_constructed.Invoke(this._transaction, pars).ToString();
        }

        /// <summary>
        /// Tries to fetch MaxKey Table Row. If not exists TableRow with Exists = false will be returned.
        /// <para>string res = tran.NonGenerics.MaxRow("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ");</para>
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode"></param>
        /// <returns></returns>
        public string MaxRow(string tableName, Type keyType, Type valueType, string selectMode)
        {
            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/MaxRowWithPossibleLocking");

            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);
            object[] pars = new object[2];
            pars[0] = tableName;
            pars[1] = selectMode.Equals("READ_SYNCHRO") ? true : false;  //we supply select mode as string can be also READ_SYNCHRO

            var rs = mi_constructed.Invoke(this._transaction, pars);

            if (rs == null)
            {
                //constructing empty Table Row 
                Type tp2 = typeof(STSdb.MTL.TableRow<,>);
                Type tb2c = tp2.MakeGenericType(keyType, valueType);

                return Activator.CreateInstance(tb2c).SerializeXml();
            }

            
            return mi_constructed.Invoke(this._transaction, pars).SerializeXml();
        }


        /// <summary>
        /// Tries to fetch MinKey Table Row. If not exists TableRow with Exists = false will be returned.
        /// <para>string res = tran.NonGenerics.MinRow("cars", Type.GetType("System.Int32"), Type.GetType("STS_wpf_tester.XCar"), "READ");</para>
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="selectMode"></param>
        /// <returns></returns>
        public string MinRow(string tableName, Type keyType, Type valueType, string selectMode)
        {
            System.Reflection.MethodInfo mi = (System.Reflection.MethodInfo)STSdb.MTL.CachedReflections.GetObject("Transaction/Method/MinRowWithPossibleLocking");

            var mi_constructed = mi.MakeGenericMethod(keyType, valueType);
            object[] pars = new object[2];
            pars[0] = tableName;
            pars[1] = selectMode.Equals("READ_SYNCHRO") ? true : false;  //we supply select mode as string can be also READ_SYNCHRO

            var rs = mi_constructed.Invoke(this._transaction, pars);

            if (rs == null)
            {
                //constructing empty Table Row 
                Type tp2 = typeof(STSdb.MTL.TableRow<,>);
                Type tb2c = tp2.MakeGenericType(keyType, valueType);

                return Activator.CreateInstance(tb2c).SerializeXml();
            }


            return mi_constructed.Invoke(this._transaction, pars).SerializeXml();
        }


        #endregion

        #region "Get Tables Information"

        /// <summary>
        /// Returns all tables names (serialized List of strings)
        /// </summary>
        /// <returns></returns>
        public string GetAllTablesNames()
        {
            return _transaction.GetAllTablesNames().SerializeXml();
        }
        #endregion
    }
}
